﻿#region Using Directives

using System;
using System.ComponentModel;
using System.IO;
using EnvDTE;
using FeatureBuilder.ContribLib.Helpers;
using Microsoft.VisualStudio.TeamArchitect.PowerTools.Features;
using VSLangProj;
using VsWebSite;

#endregion

namespace FeatureBuilder.ContribLib.Commands
{
    /// <summary>
    /// Feature Extension Command that adds a Project reference.
    /// </summary>
    [DisplayName("Add Project reference")]
    [Description("Adds a Project reference to a Project.")]
    [Category("IDE")]
    public class AddProjectReference : FeatureCommand
    {
        public Project ReferringProject { get; set; }
        public Project ReferencedProject { get; set; }
        public string ReferencedAssembly { get; set; }

        #region Overrides

        public override void Execute()
        {
            try
            {
                if (ReferencedProject != null)
                {
                    //Add project reference
                    if (ReferencedProject.UniqueName.Equals(ReferringProject.UniqueName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        return;
                    }

                    // If reference already exists, nothing happens.
                    // If referringProject is a VSProject
                    VSProject vsProject = ReferringProject.Object as VSProject;
                    if (vsProject != null)
                    {
                        if (DteHelper.IsWebProject(ReferencedProject))
                        {
                            VsWebSite.VSWebSite vsWebSite = (VsWebSite.VSWebSite)(ReferencedProject.Object);
                            foreach (VsWebSite.WebService webService in vsWebSite.WebServices)
                            {
                                vsProject.AddWebReference(webService.URL);
                            }
                        }
                        else
                        {
                            // No error handling needed here. See documentation for AddProject.
                            vsProject.References.AddProject(ReferencedProject);
                        }
                    }
                    else
                    {
                        // If the Project recived is not a VsProject
                        // Try it with a webProject
                        VSWebSite webProject = ReferringProject.Object as VSWebSite;
                        if (webProject != null)
                        {
                            if (DteHelper.IsWebProject(ReferencedProject))
                            {
                                VSWebSite vsWebSite = (VSWebSite)(ReferencedProject.Object);
                                foreach (VsWebSite.WebService webService in vsWebSite.WebServices)
                                {
                                    webProject.WebReferences.Add(webService.URL, webService.ClassName);
                                }
                            }
                            else
                            {
                                // Check if the reference already exists in the WebProject
                                if (!IsAlreadyReferenced(webProject, ReferencedProject))
                                {
                                    webProject.References.AddFromProject(ReferencedProject);
                                }
                            }
                        }
                    }
                }
                else if (ReferencedAssembly != string.Empty)
                {
                    //Add Assembly reference
                    VSProject vsProject = ReferringProject.Object as VSProject;
                    string assemblyName = Path.GetFileNameWithoutExtension(ReferencedAssembly);

                    if (vsProject != null)
                    {
                        if (!IsAlreadyReferenced(vsProject, assemblyName))
                        {
                            vsProject.References.Add(ReferencedAssembly);
                        }
                    }
                    else
                    {
                        VSWebSite webProject = ReferringProject.Object as VSWebSite;
                        if (webProject != null)
                        {
                            if (!IsAlreadyReferenced(webProject, assemblyName))
                            {
                                webProject.References.AddFromFile(ReferencedAssembly);
                            }
                        }
                    }

                }

            }
            catch { }
        }

        #endregion

        #region Privates

        private bool IsAlreadyReferenced(VSProject vsProject, string assemblyName)
        {
            bool status = false;
            foreach (Reference reference in vsProject.References)
            {
                if (reference.Name.Equals(assemblyName, StringComparison.InvariantCultureIgnoreCase))
                {
                    status = true;
                }
            }

            return status;
        }

        private bool IsAlreadyReferenced(VSWebSite webProject, string assemblyName)
        {
            bool status = false;
            foreach (AssemblyReference reference in webProject.References)
            {
                if (reference.Name.Equals(assemblyName, StringComparison.InvariantCultureIgnoreCase))
                {
                    status = true;
                }
            }

            return status;
        }

        private bool IsAlreadyReferenced(VSWebSite webProject, Project referencedProject)
        {
            bool status = false;
            foreach (AssemblyReference reference in webProject.References)
            {
                if (reference.Name.Equals(referencedProject.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    status = true;
                }
            }

            return status;
        }

        #endregion
    }
}
